using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace Serialization.Surrogates
{
    class BitmapSurrogate : ISerializationSurrogate
    {
        #region ISerializationSurrogate Members

        public void GetObjectData(object obj, SerializationInfo info)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }
            Bitmap orgBmp = (Bitmap)obj;
            info.AddValue("Width", orgBmp.Width, typeof(int));
            info.AddValue("Height", orgBmp.Height, typeof(int));
            BitmapData bmpData = null;
            try
            {
                bmpData = orgBmp.LockBits(new Rectangle(0, 0, orgBmp.Width, orgBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[bmpData.Height * bmpData.Stride];
                Marshal.Copy(bmpData.Scan0, buf, 0, buf.Length);
                info.AddValue("Data", buf, typeof(byte[]));
            }
            finally
            {
                if (bmpData != null)
                {
                    orgBmp.UnlockBits(bmpData);
                }
            }
        }

        public void SetObjectData(object obj, SerializationInfo info, ISurrogateSelector selector)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }
            byte[] data = (byte[]) info.GetValue("Data");
            int width = (int)info.GetValue("Width");
            int height = (int)info.GetValue("Height");
            ConstructorInfo ctor = typeof(Bitmap).GetConstructor(new Type[] { typeof(int), typeof(int) });
            ctor.Invoke(obj, new object[] { width, height });
            BitmapData bmpData = null;
            Bitmap bmp = (Bitmap) obj;
            try
            {
                bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
                Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
            }
            finally
            {
                if (bmpData != null)
                {
                    bmp.UnlockBits(bmpData);
                }
            }
        }

        #endregion
    }
}
